//this 既不指向函数自身，也不指函数的词法作用域。
//this的4种绑定规则分别是：默认绑定、隐式绑定、显示绑定、new 绑定。优先级从低到高。

//默认绑定
function foo(){
	console.log(this.a)
}
var a = 2

foo()  //2    "use strict" : undefined

//隐式转换
function foo() { 
    console.log( this.b );
}

var b = 2;

var obj = { 
    b: 3,
    foo: foo 
};

obj.foo(); // 3

//多层调用链
function foo(){
	console.log(this.a)
}
var a = 2;

var obj1 = {
	a:4,
	foo:foo
}

var obj2 = {
	a:3,
	obj1: obj1
}

obj2.obj1.foo()  //4


//隐式丢失（函数别名）
function foo() { 
    console.log( this.a );
}

var a = 2;

var obj = { 
    a: 3,
    foo: foo 
};

var bar = obj.foo;
bar(); //2

//通过bar找到foo函数，进行调用。整个调用过程并没有obj的参数，所以是默认绑定，全局属性a。
//函数只和他在哪调用有关

//隐式丢失（回调函数）
function foo() { 
    console.log( this.a );
}

var a = 2;

var obj = { 
    a: 3,
    foo: foo 
};

setTimeout( obj.foo, 100 ); // 2
//然参传是obj.foo，因为是引用关系，所以传参实际上传的就是foo对象本身的引用。对于setTimeout的调用，还是 setTimeout -> 获取参数中foo的引用参数 -> 执行 foo 函数，中间没有obj的参与。这里依旧进行的是默认绑定。

//显示绑定
function foo() { 
    console.log( this.a );
}

var a = 2;

var obj1 = { 
    a: 3,
};

var obj2 = { 
    a: 4,
};
foo.call( obj1 ); // 3
foo.call( obj2 ); // 4
//这里因为显示的申明了要绑定的对象，所以this就被绑定到了obj上，打印的结果自然就是obj1.a 和obj2.a。

//硬绑定
function foo() { 
    console.log( this.a );
}

var a = 2;

var obj1 = { 
    a: 3,
};

var obj2 = { 
    a: 4,
};

var bar = function(){
    foo.call( obj1 );
}

setTimeout( bar, 100 ); // 3

bar.call( obj2 ); // 这是多少  3

// 这里需要注意下，虽然bar被显示绑定到obj2上，对于bar，function(){…} 中的this确实被绑定到了obj2，而foo因为通过foo.call( obj1 )已经显示绑定了obj1，所以在foo函数内，this指向的是obj1，不会因为bar函数内指向obj2而改变自身。所以打印的是obj1.a（即3）。


// new 绑定
// js中的new操作符，和其他语言中（如JAVA）的new机制是不一样的。js中，它就是一个普通函数调用，只是被new修饰了而已。
//1.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
function foo(a){
	this.a = a;
}
var a = 2;
var bar1 = new foo(3);
console.log(bar1.a)  //3
var bar2 = new foo();  
console.log(bar2.a)  //underfined

// 绑定规则优先级

// 上面也说过，这里在重复一下。优先级是这样的，以按照下面的顺序来进行判断: 
// 数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。 
// 数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是 指定的对象。 
// 数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。 
// 果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到 全局对象。 

//规则例外
function foo(a){
	console.log(this.a)
}
var a = 2;
foo.call( null ); // 2
foo.call( undefined ); // 2


//扩展：箭头函数

//1.普通函数
function foo(){     
    console.log( this.a );
}

var a = 2;

var obj = { 
    a: 3,
    foo: foo 
};

obj.foo(); //3

//2.箭头函数

var foo = () => {
	console.log(this.a)
}

var a = 2;

var obj = {
	a:3,
	 foo: foo 
}

obj.foo()  //2
foo().call(obj)  //2






